Skip to content

fix: handle DROP TABLE CASCADE for dependent views in schema replay#4419

Open
wucm667 wants to merge 1 commit into
sqlc-dev:mainfrom
wucm667:fix/drop-table-cascade-view-replay-4416
Open

fix: handle DROP TABLE CASCADE for dependent views in schema replay#4419
wucm667 wants to merge 1 commit into
sqlc-dev:mainfrom
wucm667:fix/drop-table-cascade-view-replay-4416

Conversation

@wucm667
Copy link
Copy Markdown

@wucm667 wucm667 commented Apr 29, 2026

Problem

When sqlc generate replays a PostgreSQL schema containing DROP TABLE ... CASCADE, dependent views remain in the internal catalog. This causes subsequent CREATE VIEW statements with the same name to fail with relation "vw_reference_rates" already exists.

Minimal repro (Playground):

CREATE TABLE reference_rates (id BIGSERIAL PRIMARY KEY);
CREATE VIEW vw_reference_rates AS SELECT * FROM reference_rates;
DROP TABLE reference_rates CASCADE;
ALTER TABLE reference_rates_new RENAME TO reference_rates;
CREATE VIEW vw_reference_rates AS SELECT * FROM reference_rates;  -- fails

In real Postgres, DROP TABLE ... CASCADE drops both the table and dependent views. In sqlc's replay, the view persists.

Root Cause

  1. ast.DropTableStmt lacked a Behavior field, so the parser never captured whether CASCADE or RESTRICT was specified.
  2. dropTable() in the catalog only removed the table and linked types — it never checked for or removed dependent views.
  3. Views stored in the catalog had no dependency tracking.

Fix

1. Capture CASCADE/RESTRICT in the AST (internal/sql/ast/drop_table_stmt.go)

Added Behavior DropBehavior field.

2. Parser extracts Behavior (internal/engine/postgresql/parse.go)

When converting DropStmt for OBJECT_TABLE, OBJECT_VIEW, or OBJECT_MATVIEW, pass through n.Behavior.

3. Track view dependencies (internal/sql/catalog/view.go)

Added DependsOnTables []*ast.TableName to Table struct. The createView function now walks the SELECT query AST to extract all RangeVar (table reference) nodes, populating dependencies at view creation time.

4. CASCADE drops dependent views (internal/sql/catalog/table.go)

When Behavior == 2 (DROP_CASCADE in pg_query_go protobuf), dropTable scans all tables/views in the schema and removes any that depend on the dropped table.

5. Tests (internal/engine/postgresql/catalog_test.go)

  • TestDropTableCascadeViewRecreate: verifies CASCADE removes dependent views.
  • TestDropTableCascadeWithoutCascadeFails: verifies without CASCADE, views remain in catalog.

Testing

go test -v -count=1 ./internal/engine/postgresql/... -run "TestDropTableCascade|TestUpdateErrors"

All existing TestUpdateErrors cases pass; new CASCADE tests pass.

Fixes #4416

Signed-off-by: wucm667 <stevenwucongmin@gmail.com>
@0x4A756E65
Copy link
Copy Markdown

Would love for this to be considered - I believe it fixes my exact issue, so thank you @wucm667

@luongs3
Copy link
Copy Markdown

luongs3 commented May 28, 2026

I just closed #4456 in favor of this — I worked the same fix independently before finding yours. Same approach lands at the same place, so this is the one to merge. One thing I tried that's worth a quick consider:

In internal/sql/ast, the pg_query DropBehavior enum (UNDEFINED=0, RESTRICT=1, CASCADE=2) is checked as Behavior == 2 in dropTable(). Adding named constants in drop_behavior.go:

const (
    DropBehaviorUndefined DropBehavior = 0
    DropBehaviorRestrict  DropBehavior = 1
    DropBehaviorCascade   DropBehavior = 2
)

and using stmt.Behavior == ast.DropBehaviorCascade reads more intent-fully and would survive a future pg_query enum reshuffle. Tiny patch, no behavior change. Happy to PR it as a follow-up if you and the maintainers like it.

Otherwise this looks solid — the RangeVar walk for view DependsOn is the natural place to capture deps, and the transitive eviction handles the views-on-views case I was worried about.

@wucm667
Copy link
Copy Markdown
Author

wucm667 commented May 28, 2026

@luongs3 Thanks for the kind words and for the suggestion! I agree the named constants
would read better than == 2. If the maintainers want it, I'm happy to add it as part of
this PR or you can do a follow-up — whichever works best.

@kyleconroy @jzelinskie Would love a review when you have a moment 🙂

@luongs3
Copy link
Copy Markdown

luongs3 commented May 28, 2026

Follow-up draft up at #4461 — just the named DropBehavior constants, no use-site changes. Tagging here so it's discoverable from this thread. Happy for it to land independently before this PR, or for the rename to be folded into this PR (or a sweep PR after this merges) — whichever the maintainers prefer.

Will keep #4461 in draft until there's a signal either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostgreSQL schema parser does not drop dependent views for DROP TABLE ... CASCADE

3 participants